package com.suxin.config;

import com.suxin.algorithm.db.GoodsDbPreciseShardingAlgorithm;
import com.suxin.algorithm.table.GoodsTableCreateTimePreciseShardingAlgorithm;
import com.suxin.algorithm.table.GoodsTableCreateTimeRangeShardingAlgorithm;
import com.suxin.algorithm.table.GoodsTableIdPreciseShardingAlgorithm;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.shardingsphere.api.config.rule.ShardingRuleConfiguration;
import io.shardingsphere.api.config.rule.TableRuleConfiguration;
import io.shardingsphere.api.config.strategy.StandardShardingStrategyConfiguration;
import io.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.*;

/**
 * @author Tang
 * @classname ShardJdbcConfig
 * @description [  ]
 * @date 2021/3/9 9:46
 */
@Configuration
public class ShardJdbcConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.database0.datasource")
    public HikariConfig hikariConfig01() {
        return new HikariConfig();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.database1.datasource")
    public HikariConfig hikariConfig02() {
        return new HikariConfig();
    }

    @Bean
    public DataSource dataSource01(@Qualifier(value = "hikariConfig01") HikariConfig hikariConfig01) {
        return new HikariDataSource(hikariConfig01);
    }

    @Bean
    public DataSource dataSource02(@Qualifier(value = "hikariConfig02") HikariConfig hikariConfig02) {
        return new HikariDataSource(hikariConfig02);
    }

    @Bean
    @Primary
    public DataSource dataSource(@Autowired @Qualifier(value = "dataSource01") DataSource dataSource01,
                                 @Autowired @Qualifier(value = "dataSource02") DataSource dataSource02) throws Exception {

        Map<String, DataSource> dataSourceMap = new HashMap<String, DataSource>(16) {
            {
                put("db0", dataSource01);
                put("db1", dataSource02);
            }
        };

        Set<TableRuleConfiguration> set = new HashSet<>();
        // 规则集合
//        set.add(tableRuleConfiguration01());
        set.add(tableRuleConfiguration02());

        ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        shardingRuleConfiguration.setDefaultDataSourceName("db0");
        shardingRuleConfiguration.setTableRuleConfigs(set);

        Properties properties = new Properties();
        properties.put("sql.show", true);

        return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration,
                new HashMap<>(8), properties);
    }

    public TableRuleConfiguration tableRuleConfiguration02() {
        // 配置逻辑表
        // 配置数据节点 真实表  数据源.数据表
        TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration();
        tableRuleConfiguration.setLogicTable("goods");
        tableRuleConfiguration.setActualDataNodes("db${0..1}.goods_${2020..2021}");
        tableRuleConfiguration.setDatabaseShardingStrategyConfig(
                new StandardShardingStrategyConfiguration("goods_id", new GoodsDbPreciseShardingAlgorithm()));
        // 表分片规则  分片策略多种  =  分片键 + 分片算法
        tableRuleConfiguration.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("create_time",
                new GoodsTableCreateTimePreciseShardingAlgorithm(), new GoodsTableCreateTimeRangeShardingAlgorithm()));
        return tableRuleConfiguration;
    }

    public TableRuleConfiguration tableRuleConfiguration01() {
        // 配置逻辑表
        // 配置数据节点 真实表  数据源.数据表
        TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration();
        tableRuleConfiguration.setLogicTable("goods");
        tableRuleConfiguration.setActualDataNodes("db${0..1}.goods_${0..1}");
        // 数据库分片规则  分片策略多种  =  分片键 + 分片算法
        tableRuleConfiguration.setDatabaseShardingStrategyConfig(
                new StandardShardingStrategyConfiguration("goods_id", new GoodsDbPreciseShardingAlgorithm()));
        // 表分片规则  分片策略多种  =  分片键 + 分片算法
        tableRuleConfiguration.setTableShardingStrategyConfig(
                new StandardShardingStrategyConfiguration("goods_id", new GoodsTableIdPreciseShardingAlgorithm()));
        return tableRuleConfiguration;
    }

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        return factory.getObject();
    }

    @Bean
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.SIMPLE);
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}